#pragma once
#include <string>
#include <unordered_map>
#include <vector>
#include <sstream>
#include <iostream>
#include "Log.hpp"
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <fstream>

namespace wyl
{
#define WEBROOT "./wwwroot"
#define HOME_PAGE "index.html"
#define PAGE_404 "./wwwroot/404.html"


#define HEADER_SEP ": "

    std::unordered_map<int, std::string> _statu_msg =
        {
            {100, "Continue"},
            {101, "Switching Protocol"},
            {102, "Processing"},
            {103, "Early Hints"},
            {200, "OK"},
            {201, "Created"},
            {202, "Accepted"},
            {203, "Non-Authoritative Information"},
            {204, "No Content"},
            {205, "Reset Content"},
            {206, "Partial Content"},
            {207, "Multi-Status"},
            {208, "Already Reported"},
            {226, "IM Used"},
            {300, "Multiple Choice"},
            {301, "Moved Permanently"},
            {302, "Found"},
            {303, "See Other"},
            {304, "Not Modified"},
            {305, "Use Proxy"},
            {306, "unused"},
            {307, "Temporary Redirect"},
            {308, "Permanent Redirect"},
            {400, "Bad Request"},
            {401, "Unauthorized"},
            {402, "Payment Required"},
            {403, "Forbidden"},
            {404, "Not Found"},
            {405, "Method Not Allowed"},
            {406, "Not Acceptable"},
            {407, "Proxy Authentication Required"},
            {408, "Request Timeout"},
            {409, "Conflict"},
            {410, "Gone"},
            {411, "Length Required"},
            {412, "Precondition Failed"},
            {413, "Payload Too Large"},
            {414, "URI Too Long"},
            {415, "Unsupported Media Type"},
            {416, "Range Not Satisfiable"},
            {417, "Expectation Failed"},
            {418, "I'm a teapot"},
            {421, "Misdirected Request"},
            {422, "Unprocessable Entity"},
            {423, "Locked"},
            {424, "Failed Dependency"},
            {425, "Too Early"},
            {426, "Upgrade Required"},
            {428, "Precondition Required"},
            {429, "Too Many Requests"},
            {431, "Request Header Fields Too Large"},
            {451, "Unavailable For Legal Reasons"},
            {501, "Not Implemented"},
            {502, "Bad Gateway"},
            {503, "Service Unavailable"},
            {504, "Gateway Timeout"},
            {505, "HTTP Version Not Supported"},
            {506, "Variant Also Negotiates"},
            {507, "Insufficient Storage"},
            {508, "Loop Detected"},
            {510, "Not Extended"},
            {511, "Network Authentication Required"}};

    std::unordered_map<std::string, std::string> _mime_msg =
        {
            {".aac", "audio/aac"},
            {".abw", "application/x-abiword"},
            {".arc", "application/x-freearc"},
            {".avi", "video/x-msvideo"},
            {".azw", "application/vnd.amazon.ebook"},
            {".bin", "application/octet-stream"},
            {".bmp", "image/bmp"},
            {".bz", "application/x-bzip"},
            {".bz2", "application/x-bzip2"},
            {".csh", "application/x-csh"},
            {".css", "text/css"},
            {".csv", "text/csv"},
            {".doc", "application/msword"},
            {".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"},
            {".eot", "application/vnd.ms-fontobject"},
            {".epub", "application/epub+zip"},
            {".gif", "image/gif"},
            {".htm", "text/html"},
            {".html", "text/html"},
            {".ico", "image/vnd.microsoft.icon"},
            {".ics", "text/calendar"},
            {".jar", "application/java-archive"},
            {".jpeg", "image/jpeg"},
            {".jpg", "image/jpeg"},
            {".js", "text/javascript"},
            {".json", "application/json"},
            {".jsonld", "application/ld+json"},
            {".mid", "audio/midi"},
            {".midi", "audio/x-midi"},
            {".mjs", "text/javascript"},
            {".mp3", "audio/mpeg"},
            {".mpeg", "video/mpeg"},
            {".mpkg", "application/vnd.apple.installer+xml"},
            {".odp", "application/vnd.oasis.opendocument.presentation"},
            {".ods", "application/vnd.oasis.opendocument.spreadsheet"},
            {".odt", "application/vnd.oasis.opendocument.text"},
            {".oga", "audio/ogg"},
            {".ogv", "video/ogg"},
            {".ogx", "application/ogg"},
            {".otf", "font/otf"},
            {".png", "image/png"},
            {".pdf", "application/pdf"},
            {".ppt", "application/vnd.ms-powerpoint"},
            {".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"},
            {".rar", "application/x-rar-compressed"},
            {".rtf", "application/rtf"},
            {".sh", "application/x-sh"},
            {".svg", "image/svg+xml"},
            {".swf", "application/x-shockwave-flash"},
            {".tar", "application/x-tar"},
            {".tif", "image/tiff"},
            {".tiff", "image/tiff"},
            {".ttf", "font/ttf"},
            {".txt", "text/plain"},
            {".vsd", "application/vnd.visio"},
            {".wav", "audio/wav"},
            {".weba", "audio/webm"},
            {".webm", "video/webm"},
            {".webp", "image/webp"},
            {".woff", "font/woff"},
            {".woff2", "font/woff2"},
            {".xhtml", "application/xhtml+xml"},
            {".xls", "application/vnd.ms-excel"},
            {".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},
            {".xml", "application/xml"},
            {".xul", "application/vnd.mozilla.xul+xml"},
            {".zip", "application/zip"},
            {".3gp", "video/3gpp"},
            {".3g2", "video/3gpp2"},
            {".7z", "application/x-7z-compressed"}};

    class Response;

    class Request
    {
    public:
        Request():_ishandler(false){}

        bool Parse(std::string &request)
        {
            //std::cout << "--------------------------------------" << std::endl;
            //logMessage(DEBUG,"%s",request.c_str());
            //std::cout << "--------------------------------------" << std::endl;

            // 1.解析请求行
            if(!ParseReqLine(request))
            {
                return false;
            }
                   // 2.解析请求报头
            ParseReqHeader(request); 
            // 3.解析正文
            if(_method == "POST")
            {
                _ishandler = true;
                ParseReqBody(request);
            }
            return true;
        }
        std::string& Path(){return _path;}

        bool ParseReqLine(std::string &request)
        {
            _req_line = Util::GetLine(request);
            std::stringstream line(_req_line);
            line >> _method >> _url >> _httpversion;
            size_t pos = _url.find("./");
            if(pos != std::string::npos)
            {
                return false;
            }
            ParseReqUrl();
           
         //  logMessage(DEBUG, "%s %s %s  path : %s", _method.c_str(), _url.c_str(), _httpversion.c_str(), _path.c_str());
          //  logMessage(DEBUG, "_req_line : %s", _req_line.c_str());
            return true;
        }
        void  ParseReqUrl()
        {
            //   /index?username=100&password=100
            std::string req_url; 
            std::string req_msg; 
            if(!Util::CutString(_url,&req_url,&req_msg,"?") && _method == "GET")
            {
                //说明是静态资源请求
                _ishandler = false;
                _path = WEBROOT;
                 _path += _url;
                if (_path[_path.size() - 1] == '/')
                    _path += HOME_PAGE;
                return;
            }
            _ishandler =  true;
            _path = WEBROOT;
            _path += req_url;
            if (_path[_path.size() - 1] == '/')
                    _path += HOME_PAGE;
        }


        bool ParseReqHeader(std::string &request)
        {
            std::string line;
           // logMessage(DEBUG, "request : %s", request.c_str());
            while ((line = Util::GetLine(request)) != "")
            {
                // Content-Length: 10
            //      logMessage(DEBUG,"line : %s",line.c_str());
                std::string key, value;
                size_t pos = line.find(HEADER_SEP);
                if (pos == std::string::npos)
                {
                    //  logMessage(DEBUG,"pos : %d",pos);
                    // request error
                    break;
                }
                // 0 - pos , pos + 1 ....
                key = line.substr(0, pos);
                value = line.substr(pos + 1);
                _header.insert(std::make_pair(key, value));
          //      logMessage(DEBUG, "key : %s", key.c_str());
           //     logMessage(DEBUG, "value : %s", value.c_str());
            }
            return true;
        }

        bool ParseReqBody(std::string &request)
        {
            auto it = _header.find("Content-Length");
            if (it == _header.end())
            {
                // the request have no body
                return true;
            }
            _content_len = atoi(it->second.c_str());
            std::string body = request.substr(0, _content_len);
            request.erase(0,_content_len);
        //    logMessage(DEBUG, "body : %s", _body.c_str());

            //对body进行解码
            _body = Util::Decode(body);
            logMessage(DEBUG,"parse req_body : %s",_body.c_str());
            return true;
        }

        std::string GetRequestBody()const{return _body;}
        std::string GetRequestLine()const{return _req_line;}
        std::string GetRequestMethod()const{return _method;}


        std::string GetSuffix()
        {
            size_t pos = _path.rfind(".");
            return _path.substr(pos);
        }

        bool IsHandler()const{return _ishandler;}
        void clean()
        {
            _method.clear();
            _url.clear();
            _path.clear();
            _req_line.clear();
            _header.clear();
            _body.clear();
            _content_len = 0;
            _ishandler = false;
        }        
    private:
        // GET / HTTP/1.0
        std::string _method;
        std::string _url;
        std::string _httpversion;
        std::string _path;

        std::string _req_line;                                // 请求行
        std::unordered_map<std::string, std::string> _header; // 请求报头
        std::string _body;                                    // 请求正文
        size_t _content_len;
        bool _ishandler;

    };

    class Response
    {
    public:
        Response(int sock = -1) :_statu_code(200),_sock(sock),_httpversion("HTTP/1.1") {}
        void SetStatuCode(int err_code){_statu_code = err_code;}

        //添加报头
        void SetHeader(const std::string& key,const std::string& value)
        {
           _resp_header.insert(std::make_pair(key,value));
        }
        //设置正文
         void SetBody(const std::string& path)
         {
            logMessage(NORMAL,"begin to set Body....");
            std::string* context = GetContext(path);
            if(context == nullptr)
            {
                _statu_code = 404;
                return;
                //context = GetContext(PAGE_404);
            }
        //    logMessage(NORMAL,"返回内容 ： %s",context->c_str());
            //设置正文长度报头
            SetHeader("Content-Length",std::to_string(context->size()));
            _resp_body = *context;
         }


        //send组织响应并发送
         void Send()
         {
            std::string mesg;
            BuildRespLine();
            mesg += _resp_line;
            mesg += BuildRespHeader();
            mesg += "\r\n"; 
            mesg += _resp_body;

         //   logMessage(NORMAL,"begin send....:\n%s",mesg.c_str());
            write(_sock,mesg.c_str(),mesg.size());
         }

    private:
        //  std::string BuildResponse(const std::string _path)
        //  {
        //     logMessage(NORMAL,"begin build....");
        //     std::string resp_str;
        //     BuildRespLine();
        //     SetBody(_path);
        //     resp_str += _resp_line; 
        //     resp_str += BuildRespHeader();
        //     resp_str += "\r\n";
        //     resp_str += _resp_body;
        //     logMessage(NORMAL,"begin end...., resp : \n%s",resp_str.c_str());
        //     return resp_str;
        //  }
         void Clean()
         {
            _statu_code = 200;
            _resp_line.clear();
            _resp_header.clear();
            _resp_body.clear();
         }
    
    private:
        //返回文件中的字符串
        std::string* GetContext(const std::string& path)
        {
            int fd = open(path.c_str(),O_RDWR);
            if(fd < 0)
            {
                return nullptr;
            }
            char buff[1024 * 1024 * 4] = {0};
            int n = read(fd,buff,sizeof buff -1);
            buff[n] = 0 ;
            std::string* context = new std::string((std::string::iterator)&buff[0],(std::string::iterator)&buff[n]); 
            //logMessage(NORMAL,"context : \n%s" ,context->c_str());
            close(fd);
            return context;
        }


        bool BuildRespLine()
        {
            _resp_line = _httpversion + " " + std::to_string(_statu_code) + " " + _statu_msg[200] + "\r\n";
            logMessage(NORMAL,"build response line.... : \n%s",_resp_line.c_str());
            return true;
        }
        std::string BuildRespHeader()
        {
            logMessage(NORMAL,"build response header....");
            std::string header;
            for(auto& it : _resp_header)
            {
                header += it.first;
                header += HEADER_SEP;
                header += it.second;
                header += "\r\n";
            }
            logMessage(NORMAL,"build response header success....:\n%s",header.c_str());
            return header;
        }

    private:
        int _statu_code;
        int _sock;
        std::string _httpversion;
        std::string _resp_line;
        std::unordered_map<std::string,std::string> _resp_header;
        std::string _resp_body;
    };
};